﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace Gauss.Isp
{
    public partial class IspStepperGui : Form
    {
        #region Static Color Variables

        private static readonly Color Color_CurrentCall = Color.Orange;
        private static readonly Color Color_MatchingCollective = Color.SkyBlue;
        private static readonly Color Color_MatchingP2P = Color.LightGreen;
        private static readonly Color Color_UnissuedCall = Color.LightPink;

        #endregion

        #region Member Variables

        private Transitions _transitions;
        private TransitionNavigator _transitionNavigator;
        private RichTextBox _mainTextBox;
        private Label _mainTextBoxLabel;
        private TableLayoutPanel _additionalTextBoxesLayoutPanel;
        private List<RichTextBox> _additionalTextBoxes;
        private List<Label> _additionalTextBoxLabels;
        private Label _lblInterleaving;
        private List<Highlight> _highlights;
        private int _lockToRank;
        private Button _btnFirstTransition;
        private Button _btnNextTransition;
        private Button _btnPreviousTransition;
        private Button _btnLastTransition;
        private Button _btnFirstInterleaving;
        private Button _btnPreviousInterleaving;
        private Button _btnNextInterleaving;
        private Button _btnLastInterleaving;
        
        private Button _btnStartDebugging;
        private bool _debugProject;
        private IEnumerable<Envelope> _debugInterleaving;
        private Envelope _debugTransition;

        #endregion

        #region Properties

        public bool DebugProject
        {
            get { return _debugProject; }
        }

        public IEnumerable<Envelope> DebugInterleaving
        {
            get { return _debugInterleaving; }
        }

        public Envelope DebugTransition
        {
            get { return _debugTransition; }
        }

        #endregion

        #region Constructor

        public IspStepperGui(string logfile, bool useIssueOrder)
        {
            InitializeComponent();

            _lockToRank = -1;
            _transitions = new Transitions(logfile, useIssueOrder);

            Envelope env = _transitions.NextTransition(_lockToRank);
            if (env == null)
            {
                throw new NoMpiCallException();
            }

            // Setup the table.
            _tableLayoutPanel.RowCount = 3;
            _tableLayoutPanel.RowStyles.Clear();
            _tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
            _tableLayoutPanel.RowStyles.Add(new RowStyle());
            _tableLayoutPanel.RowStyles.Add(new RowStyle());
            _tableLayoutPanel.ColumnCount = 2;
            _tableLayoutPanel.ColumnStyles.Clear();
            _tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50));
            _tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50));

            // Setup the top panel.
            FlowLayoutPanel topPanel = new FlowLayoutPanel();
            _tableLayoutPanel.Controls.Add(topPanel);
            _tableLayoutPanel.SetColumnSpan(topPanel, _tableLayoutPanel.RowCount);
            topPanel.Dock = DockStyle.Fill;
            topPanel.Anchor = AnchorStyles.Left | AnchorStyles.Right;

            // Transition stepping buttons
            _btnFirstTransition = new Button();
            _btnFirstTransition.Text = "<<";
            _btnFirstTransition.Width = 35;
            _btnFirstTransition.Click += new EventHandler(FirstTransition_Click);
            _btnFirstTransition.Anchor = AnchorStyles.None;

            _btnPreviousTransition = new Button();
            _btnPreviousTransition.Text = "<";
            _btnPreviousTransition.Width = 25;
            _btnPreviousTransition.Click += new EventHandler(PreviousTransition_Click);
            _btnPreviousTransition.Anchor = AnchorStyles.None;

            _btnNextTransition = new Button();
            _btnNextTransition.Text = ">";
            _btnNextTransition.Width = 25;
            _btnNextTransition.Click += new EventHandler(NextTransition_Click);
            _btnNextTransition.Anchor = AnchorStyles.None;

            _btnLastTransition = new Button();
            _btnLastTransition.Text = ">>";
            _btnLastTransition.Width = 35;
            _btnLastTransition.Click += new EventHandler(LastTransition_Click);
            _btnLastTransition.Anchor = AnchorStyles.None;

            Button btnListTransitions = new Button();
            btnListTransitions.Text = "Browse";
            btnListTransitions.AutoSize = true;
            btnListTransitions.Click += new EventHandler(TransitionList_Click);
            btnListTransitions.Anchor = AnchorStyles.None;

            //////THIS SECTION IS FOR TRIGGERING http://karma.cs.utah.edu:8080/show_bug.cgi?id=25
            //Button _btnTriggerWinException = new Button();
            //_btnTriggerWinException.Text = "BreakMe";
            //_btnTriggerWinException.AutoSize = true;
            //_btnTriggerWinException.Click += new EventHandler(
            //    delegate
            //    {
            //        bool forward = true;
            //        //while (_transitions.HasNextInterleaving)
            //        //{
            //        //delegate {
            //        Timer timer = new Timer();
            //        timer.Tick += new EventHandler(delegate
            //        {
            //            timer.Enabled = false;
            //            bool enableTimer = true;
            //            if (forward)
            //            {
            //                if (_transitions.HasNextTransition)
            //                {
            //                    _btnNextTransition.PerformClick();
            //                }
            //                else
            //                {
            //                    forward = false;
            //                }
            //            }
            //            else
            //            {
            //                if (_transitions.HasPreviousTransition)
            //                {
            //                    _btnPreviousTransition.PerformClick();
            //                }
            //                else
            //                {
            //                    if (_transitions.HasNextInterleaving)
            //                    {
            //                        forward = true;
            //                        _btnNextInterleaving.PerformClick();
            //                    }
            //                    else
            //                    {
            //                        enableTimer = false;
            //                    }
            //                }
            //            }
            //            timer.Enabled = enableTimer;
            //        });
            //        timer.Enabled = true;
            //        timer.Interval = 50;
            //        //Application.DoEvents();

            //    });
            //_btnTriggerWinException.Anchor = AnchorStyles.None;


            _btnStartDebugging = new Button();
            _btnStartDebugging.Text = "Debug";
            _btnStartDebugging.AutoSize = true;
            _btnStartDebugging.Click += new EventHandler(StartDebugging_Click);
            _btnStartDebugging.Anchor = AnchorStyles.None;
            _btnStartDebugging.Visible = false; //TODO: remove, if debugging support is implemented



            ComboBox cmbLockToRank = new ComboBox();
            cmbLockToRank.Items.Add("No Ranks Locked");
            for (int i = 0; i < _transitions.Ranks; i++)
            {
                cmbLockToRank.Items.Add(i + " Locked");
            }
            cmbLockToRank.SelectedIndex = 0;
            cmbLockToRank.DropDownStyle = ComboBoxStyle.DropDownList;
            cmbLockToRank.SelectedValueChanged += new EventHandler(cmbLockToRank_ValueChanged);
            Padding padding = cmbLockToRank.Margin;
            padding.Left = 15;
            padding.Right = 15;
            cmbLockToRank.Margin = padding;

            FlowLayoutPanel transitionsFlowLayoutPanel = new FlowLayoutPanel();
            transitionsFlowLayoutPanel.Controls.Add(_btnFirstTransition);
            transitionsFlowLayoutPanel.Controls.Add(_btnPreviousTransition);
            transitionsFlowLayoutPanel.Controls.Add(_btnNextTransition);
            transitionsFlowLayoutPanel.Controls.Add(_btnLastTransition);
            transitionsFlowLayoutPanel.Controls.Add(btnListTransitions);
            transitionsFlowLayoutPanel.Controls.Add(_btnStartDebugging);
            //transitionsFlowLayoutPanel.Controls.Add(_btnTriggerWinException);
            transitionsFlowLayoutPanel.Controls.Add(cmbLockToRank);
            transitionsFlowLayoutPanel.Dock = DockStyle.Fill;
            transitionsFlowLayoutPanel.AutoSize = true;

            GroupBox transitionGroupBox = new GroupBox();
            transitionGroupBox.Text = "Transitions";
            transitionGroupBox.Controls.Add(transitionsFlowLayoutPanel);
            transitionGroupBox.AutoSize = true;
            topPanel.Controls.Add(transitionGroupBox);

            // Interleaving stepping buttons.
            _btnFirstInterleaving = new Button();
            _btnFirstInterleaving.Text = "<<";
            _btnFirstInterleaving.Width = 35;
            _btnFirstInterleaving.Click += new EventHandler(FirstInterleaving_Click);
            _btnFirstInterleaving.Anchor = AnchorStyles.None;
            
            _btnPreviousInterleaving = new Button();
            _btnPreviousInterleaving.Text = "<";
            _btnPreviousInterleaving.Width = 25;
            _btnPreviousInterleaving.Click += new EventHandler(PreviousInterleaving_Click);
            _btnPreviousInterleaving.Anchor = AnchorStyles.None;

            _btnNextInterleaving = new Button();
            _btnNextInterleaving.Text = ">";
            _btnNextInterleaving.Width = 25;
            _btnNextInterleaving.Click += new EventHandler(NextInterleaving_Click);
            _btnNextInterleaving.Anchor = AnchorStyles.None;

            _btnLastInterleaving = new Button();
            _btnLastInterleaving.Text = ">>";
            _btnLastInterleaving.Width = 35;
            _btnLastInterleaving.Click += new EventHandler(LastInterleaving_Click);
            _btnLastInterleaving.Anchor = AnchorStyles.None;

            _lblInterleaving = new Label();
            _lblInterleaving.Text = "Interleaving: " + _transitions.CurrentInterleaving + "/" + _transitions.TotalInterleavings;
            padding = _lblInterleaving.Margin;
            padding.Top = 6;
            padding.Left = 15;
            _lblInterleaving.Margin = padding;
            _lblInterleaving.Padding = Padding.Empty;
            _lblInterleaving.AutoSize = true;

            Label lblDeadlock = new Label();
            padding = lblDeadlock.Margin;
            if (_transitions.Deadlock)
            {
                lblDeadlock.Text = "Deadlock found\nin Interleaving " + _transitions.TotalInterleavings;
                lblDeadlock.ForeColor = Color.Red;
                padding.Top = 0;
            }
            else if (_transitions.AssertionFailure)
            {
                lblDeadlock.Text = "Assertion violation found\nin Interleaving " + _transitions.TotalInterleavings;
                lblDeadlock.ForeColor = Color.Red;
                padding.Top = 0;
            }
            else
            {
                lblDeadlock.Text = "No Deadlocks";
                padding.Top = 6;
            }
            padding.Left = 15;
            padding.Right = 15;
            lblDeadlock.Margin = padding;
            lblDeadlock.AutoSize = true;
            lblDeadlock.Padding = Padding.Empty;

            FlowLayoutPanel interleavingsFlowLayoutPanel = new FlowLayoutPanel();
            interleavingsFlowLayoutPanel.Controls.Add(_btnFirstInterleaving);
            interleavingsFlowLayoutPanel.Controls.Add(_btnPreviousInterleaving);
            interleavingsFlowLayoutPanel.Controls.Add(_btnNextInterleaving);
            interleavingsFlowLayoutPanel.Controls.Add(_btnLastInterleaving);
            interleavingsFlowLayoutPanel.Controls.Add(_lblInterleaving);
            interleavingsFlowLayoutPanel.Controls.Add(lblDeadlock);
            interleavingsFlowLayoutPanel.Dock = DockStyle.Fill;
            interleavingsFlowLayoutPanel.AutoSize = true;

            GroupBox interleavingGroupBox = new GroupBox();
            interleavingGroupBox.Text = "Interleavings";
            interleavingGroupBox.Controls.Add(interleavingsFlowLayoutPanel);
            interleavingGroupBox.AutoSize = true;
            topPanel.Controls.Add(interleavingGroupBox);

            int maxHeight = 0;
            foreach (Control c in topPanel.Controls)
            {
                if (c.Height > maxHeight)
                    maxHeight = c.Height;
            }
            topPanel.Height = maxHeight + 5;

            // Setup the Legend display.
            Label lblLegend_CurrentCall = new Label();
            lblLegend_CurrentCall.AutoSize = true;
            lblLegend_CurrentCall.BackColor = Color_CurrentCall;
            lblLegend_CurrentCall.Text = "Active MPI Call";
            lblLegend_CurrentCall.Margin = new Padding(0, 0, 0, 1);
            lblLegend_CurrentCall.Padding = new Padding(0);

            Label lblLegend_UnissuedCall = new Label();
            lblLegend_UnissuedCall.AutoSize = true;
            lblLegend_UnissuedCall.BackColor = Color_UnissuedCall;
            lblLegend_UnissuedCall.Text = "Unissued MPI Call / Assertion";
            lblLegend_UnissuedCall.Margin = new Padding(0);
            lblLegend_UnissuedCall.Padding = new Padding(0);

            Label lblLegend_MatchingCollective = new Label();
            lblLegend_MatchingCollective.AutoSize = true;
            lblLegend_MatchingCollective.BackColor = Color_MatchingCollective;
            lblLegend_MatchingCollective.Text = "Matching Collective Call";
            lblLegend_MatchingCollective.Margin = new Padding(0, 0, 0, 1);
            lblLegend_MatchingCollective.Padding = new Padding(0);

            Label lblLegend_MatchingP2P = new Label();
            lblLegend_MatchingP2P.AutoSize = true;
            lblLegend_MatchingP2P.BackColor = Color_MatchingP2P;
            lblLegend_MatchingP2P.Text = "Matching Point-to-Point Call";
            lblLegend_MatchingP2P.Margin = new Padding(0);
            lblLegend_MatchingP2P.Padding = new Padding(0);

            FlowLayoutPanel legendFlowLayoutPanelLeft = new FlowLayoutPanel();
            legendFlowLayoutPanelLeft.Controls.Add(lblLegend_CurrentCall);
            legendFlowLayoutPanelLeft.Controls.Add(lblLegend_UnissuedCall);
            legendFlowLayoutPanelLeft.Anchor = AnchorStyles.Left;
            legendFlowLayoutPanelLeft.AutoSize = true;
            legendFlowLayoutPanelLeft.FlowDirection = FlowDirection.TopDown;

            FlowLayoutPanel legendFlowLayoutPanelRight = new FlowLayoutPanel();
            legendFlowLayoutPanelRight.Controls.Add(lblLegend_MatchingCollective);
            legendFlowLayoutPanelRight.Controls.Add(lblLegend_MatchingP2P);
            legendFlowLayoutPanelRight.Anchor = AnchorStyles.Left;
            legendFlowLayoutPanelRight.AutoSize = true;
            legendFlowLayoutPanelRight.FlowDirection = FlowDirection.TopDown;

            FlowLayoutPanel legendFlowLayoutPanel = new FlowLayoutPanel();
            legendFlowLayoutPanel.Controls.Add(legendFlowLayoutPanelLeft);
            legendFlowLayoutPanel.Controls.Add(legendFlowLayoutPanelRight);
            legendFlowLayoutPanel.Anchor = AnchorStyles.Left;
            legendFlowLayoutPanel.AutoSize = true;
            legendFlowLayoutPanel.FlowDirection = FlowDirection.LeftToRight;

            GroupBox legendGroupBox = new GroupBox();
            legendGroupBox.Text = "Legend";
            legendGroupBox.Controls.Add(legendFlowLayoutPanel);
            legendGroupBox.AutoSize = true;
            legendGroupBox.Margin = new Padding(10, 0, 10, 0);
            legendGroupBox.Padding = new Padding(10, 0, 10, 0);
            topPanel.Controls.Add(legendGroupBox);

            // Setup the initial text box.
            _mainTextBox = new RichTextBox();
            _mainTextBox.WordWrap = false;
            _mainTextBox.Dock = DockStyle.Fill;
            _mainTextBox.ReadOnly = true;
            _mainTextBox.BackColor = Color.White;
            _tableLayoutPanel.Controls.Add(_mainTextBox, 0, 2);
            _highlights = new List<Highlight>();
            _mainTextBoxLabel = new Label();
            _mainTextBoxLabel.Dock = DockStyle.Fill;
            _mainTextBoxLabel.AutoSize = true;
            _tableLayoutPanel.Controls.Add(_mainTextBoxLabel, 0, 1);

            // Setup the lists for the additional text boxes.
            _additionalTextBoxes = new List<RichTextBox>();
            _additionalTextBoxLabels = new List<Label>();
            _additionalTextBoxesLayoutPanel = new TableLayoutPanel();
            _additionalTextBoxesLayoutPanel.Dock = DockStyle.Fill;
            _additionalTextBoxesLayoutPanel.ColumnCount = 1;
            _additionalTextBoxesLayoutPanel.ColumnStyles.Clear();
            _additionalTextBoxesLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            _additionalTextBoxesLayoutPanel.RowCount = 0;
            _additionalTextBoxesLayoutPanel.RowStyles.Clear();
            _tableLayoutPanel.Controls.Add(_additionalTextBoxesLayoutPanel, 1, 1);
            _tableLayoutPanel.SetRowSpan(_additionalTextBoxesLayoutPanel, 2);

            // Setup the button appropriately.
            ResetButtonEnabledState();

            // Finally, this displays the envelope in the appropriate format.
            DisplayEnvelope(env);
        }

        #endregion

        #region Transition Buttons

        private void FirstTransition_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                Envelope env = _transitions.StepToFirstTransition(_lockToRank);
                if (env == null)
                {
                    Utils.MessageBox(null, Resources.SourceAnalyzer_NoPrevTransitions);
                    return;
                }

                ResetButtonEnabledState();

                DisplayEnvelope(env);
            }
        }

        private void PreviousTransition_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                Envelope env = _transitions.PreviousTransition(_lockToRank);
                if (env == null)
                {
                    Utils.MessageBox(null, Resources.SourceAnalyzer_NoPrevTransitions);
                    return;
                }

                ResetButtonEnabledState();

                DisplayEnvelope(env);
            }
        }

        private void NextTransition_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                Envelope env = _transitions.NextTransition(_lockToRank);
                if (env == null)
                {
                    Utils.MessageBox(null, Resources.SourceAnalyzer_NoNextTransitions);
                    return;
                }

                ResetButtonEnabledState();

                DisplayEnvelope(env);
            }
        }

        private void LastTransition_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                Envelope env = _transitions.StepToLastTransition(_lockToRank);
                if (env == null)
                {
                    Utils.MessageBox(null, Resources.SourceAnalyzer_NoNextTransitions);
                    return;
                }

                ResetButtonEnabledState();

                DisplayEnvelope(env);
            }
        }

        #endregion

        #region Transition Navigator Event Handlers

        private void TransitionList_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                if (_transitionNavigator != null)
                {
                    return;
                }

                _transitionNavigator = new TransitionNavigator(_transitions);
                _transitionNavigator.EnvelopeClicked += new EventHandler<TransitionNavigator.EnvelopeClickedEventArgs>(TransitionNavigator_EnvelopeClicked);
                _transitionNavigator.FormClosed += new FormClosedEventHandler(TransitionNavigator_FormClosed);
                _transitionNavigator.SelectedEnvelope = _transitions.GetCurrentTransition();
                _transitionNavigator.Interleaving = _transitions.CurrentInterleaving;
                _transitionNavigator.Show(this);
            }
        }

        private void StartDebugging_Click(object sender, EventArgs e)
        {
            _debugProject = true;
            _debugInterleaving = _transitions.GetEnvelopesInInterleaving(_transitions.CurrentInterleaving);
            _debugTransition = _transitions.GetCurrentTransition();
            Close();
        }

        private void TransitionNavigator_FormClosed(object sender, FormClosedEventArgs e)
        {
            lock (this)
            {
                _transitionNavigator.Dispose();
                _transitionNavigator = null;
            }
        }

        private void TransitionNavigator_EnvelopeClicked(object sender, TransitionNavigator.EnvelopeClickedEventArgs e)
        {
            lock (this)
            {
                Envelope envelope = _transitions.SetCurrentTransition(e.Envelope);

                if (envelope != null)
                {
                    ResetButtonEnabledState();

                    DisplayEnvelope(envelope);
                }
            }
        }

        #endregion

        #region Interleaving Buttons

        private void FirstInterleaving_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                if (_transitions.HasPreviousInterleaving)
                {
                    while (_transitions.PreviousInterleaving())
                        ;

                    _lblInterleaving.Text = "Interleaving: " + _transitions.CurrentInterleaving + "/" + _transitions.TotalInterleavings;
                    NextTransition_Click(null, null);
                }
                else
                {
                    Utils.MessageBox(null, Resources.SourceAnalyzer_NoPrevInterleavings);
                }
            }
        }

        private void PreviousInterleaving_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                if (_transitions.PreviousInterleaving())
                {
                    _lblInterleaving.Text = "Interleaving: " + _transitions.CurrentInterleaving + "/" + _transitions.TotalInterleavings;
                    NextTransition_Click(null, null);
                }
                else
                {
                    Utils.MessageBox(null, Resources.SourceAnalyzer_NoPrevInterleavings);
                }
            }
        }

        private void NextInterleaving_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                if (_transitions.NextInterleaving())
                {
                    _lblInterleaving.Text = "Interleaving: " + _transitions.CurrentInterleaving + "/" + _transitions.TotalInterleavings;
                    NextTransition_Click(null, null);
                }
                else
                {
                    Utils.MessageBox(null, Resources.SourceAnaylzer_NoNextInterleavings);
                }
            }
        }

        private void LastInterleaving_Click(object sender, EventArgs e)
        {
            lock (this)
            {
                if (_transitions.HasNextInterleaving)
                {
                    while (_transitions.NextInterleaving())
                        ;

                    _lblInterleaving.Text = "Interleaving: " + _transitions.CurrentInterleaving + "/" + _transitions.TotalInterleavings;
                    NextTransition_Click(null, null);
                }
                else
                {
                    Utils.MessageBox(null, Resources.SourceAnaylzer_NoNextInterleavings);
                }
            }
        }

        #endregion

        #region RichTextBox Highlighting

        private void HighlightMpiCall(Highlight highlight)
        {
            RichTextBox richTextBox = highlight.TextBox;

            int start = richTextBox.SelectionStart;
            int length = richTextBox.SelectionLength;
            int linenumber = highlight.LineNumber;
            int index = -1;
            for (int i = 0; i < linenumber; i++)
            {
                index = richTextBox.Text.IndexOf("\n", index + 1);
                if (index == -1)
                    break;
            }
            if (index < 0)
            {
                Utils.MessageBox(null, Utils.StringFormat(Resources.SourceAnalyzer_CouldNotFindMpiCall, highlight.MpiCallName));
                richTextBox.SelectionStart = start;
                richTextBox.SelectionLength = length;
                return;
            }

            int indx = index - 1;
            //find beginning of line
            while (indx > 0 && richTextBox.Text[indx] != '\n') --indx;
            while (indx < richTextBox.Text.Length && (richTextBox.Text[indx] == '\n' ||
                    richTextBox.Text[indx] == ' ' || richTextBox.Text[indx] == '\t')) ++indx;

            richTextBox.SelectionStart = indx;
            richTextBox.SelectionLength = index - indx;



            //going to redo the rest of this function -- we have the right line, let's just highlight the text on it!

            #region old

            //// Start at the end of the line, looking for the first ')'.
            //int startPosition = -1;
            //int endPosition = -1;
            //for (int position = index - 1; position >= 0; position--)
            //{
            //    // Find the closing paren.
            //    richTextBox.SelectionStart = position;
            //    richTextBox.SelectionLength = 1;
            //    if (richTextBox.SelectedText == "\n")
            //    {
            //        break;
            //    }
            //    else if (richTextBox.SelectedText != ")")
            //    {
            //        continue;
            //    }

            //    // Find the opening paren.
            //    int balanced = 1;
            //    while (balanced > 0)
            //    {
            //        if (richTextBox.SelectionStart == 0)
            //        {
            //            break;
            //        }
            //        richTextBox.SelectionStart--;
            //        if (richTextBox.SelectedText == ")")
            //            balanced++;
            //        else if (richTextBox.SelectedText == "(")
            //            balanced--;
            //    }
            //    if (balanced != 0)
            //        break;

            //    // Remove whitespace between the FunctionName and '('.
            //    do
            //    {
            //        if (richTextBox.SelectionStart == 0)
            //            break;
            //        richTextBox.SelectionStart--;
            //    } while (richTextBox.SelectedText == " " || richTextBox.SelectedText == "\t");
            //    if (richTextBox.SelectionStart == 0)
            //        break;

            //    // Find the function name.
            //    if (richTextBox.SelectionStart - highlight.MpiCallName.Length - 1 < 0)
            //        break;
            //    richTextBox.SelectionStart -= highlight.MpiCallName.Length - 1;
            //    richTextBox.SelectionLength = highlight.MpiCallName.Length;
            //    //if (richTextBox.SelectedText == highlight.MpiCallName) 
            //    //{
            //    startPosition = richTextBox.SelectionStart;
            //    endPosition = position;
            //    break;
            //    //}
            //}
            //if (startPosition < 0 || endPosition < 0)
            //{
            //    Utils.MessageBox(null, Utils.StringFormat(Resources.SourceAnalyzer_CouldNotFindMpiCall, highlight.MpiCallName));
            //    richTextBox.SelectionStart = start;
            //    richTextBox.SelectionLength = length;
            //    return;
            //}

            //richTextBox.SelectionStart = startPosition;
            ////while (richTextBox.Text[startPosition] != '\n') --startPosition; //this is a bit hackey -- find beginning of line instead
            //richTextBox.SelectionStart = startPosition + 1;
            //richTextBox.SelectionLength = (endPosition - startPosition) + 1;
            #endregion
            richTextBox.SelectionBackColor = highlight.HighlightColor;
            try
            {
                richTextBox.ScrollToCaret();
            }
            catch { }
            highlight.Highlighted = true;
            highlight.StartPosition = richTextBox.SelectionStart;
            highlight.HighlightLength = richTextBox.SelectionLength;
            //richTextBox.SelectionStart = start;
            //richTextBox.SelectionLength = length;

            _highlights.Add(highlight);
        }

        private void RemoveHighlight(Highlight highlight)
        {
            if (highlight == null || !highlight.Highlighted)
            {
                return;
            }

            RichTextBox richTextBox = highlight.TextBox;
            int start = richTextBox.SelectionStart;
            if (start > richTextBox.Text.Length)
                start = richTextBox.Text.Length;
            int length = richTextBox.SelectionLength;
            if (start + length > richTextBox.Text.Length)
                length = richTextBox.Text.Length - start;
            richTextBox.SelectionStart = highlight.StartPosition;
            richTextBox.SelectionLength = highlight.HighlightLength;
            richTextBox.SelectionBackColor = richTextBox.BackColor;
            richTextBox.SelectionColor = richTextBox.ForeColor;
            richTextBox.SelectionStart = start;
            richTextBox.SelectionLength = length;
        }

        private class Highlight
        {
            public bool Highlighted;
            public int StartPosition;
            public int HighlightLength;
            public string FileName;
            public int LineNumber;
            public string MpiCallName;
            public Color HighlightColor;
            public RichTextBox TextBox;

            public Highlight(Envelope env, RichTextBox textbox, Color highlightcolor)
            {
                this.FileName = env.FileName;
                this.LineNumber = env.LineNumber;
                this.MpiCallName = env.MpiCallName;
                this.TextBox = textbox;
                this.HighlightColor = highlightcolor;
            }
        }

        #endregion

        #region LockToRank Events

        void cmbLockToRank_ValueChanged(object sender, EventArgs e)
        {
            lock (this)
            {
                ComboBox cb = sender as ComboBox;
                if (cb == null)
                {
                    return;
                }

                string firstPart = cb.Items[cb.SelectedIndex] as string;
                if (firstPart == null)
                {
                    _lockToRank = -1;
                }
                else
                {
                    if (!Utils.TryParseInt(firstPart.Substring(0, firstPart.IndexOf(' ')), out _lockToRank))
                    {
                        _lockToRank = -1;
                    }
                }
            }
        }

        #endregion

        #region Helper Functions

        private void DisplayEnvelope(Envelope env)
        {
            // Show in Transition Navigator if open.
            if (_transitionNavigator != null)
            {
                _transitionNavigator.SelectedEnvelope = env;
            }

            // First, remove all of the highlights.
            foreach (Highlight highlight in _highlights)
            {
                RemoveHighlight(highlight);
            }
            _highlights.Clear();

            // Next, load the appropriate file in to the main text box.
            _mainTextBoxLabel.Text = Utils.StringFormat(Resources.SourceAnalyzer_TextBoxCaption, env.Rank, env.FileName, env.LineNumber, env.ToString());
            if (env.FileName.ToUpperInvariant() != _mainTextBox.Tag as string)
            {
                _mainTextBox.Text = "";
                if (env.LineNumber < 0)
                {
                    _mainTextBox.Text = Resources.SourceAnalyzer_UnknownFile;
                    _mainTextBoxLabel.Text = Utils.StringFormat(Resources.SourceAnalyzer_TextBoxCaption_UnknownFile, env.Rank, env.ToString());
                }
                else
                {
                    try
                    {
                        using (StreamReader sr = new StreamReader(env.FileName))
                        {
                            _mainTextBox.Text = sr.ReadToEnd();
                        }
                        _mainTextBox.Tag = env.FileName.ToUpperInvariant();

                        // Highlight the correct function for the "main" window.
                        if (env.IssueIndex < 0)
                            HighlightMpiCall(new Highlight(env, _mainTextBox, Color_UnissuedCall));
                        else
                            HighlightMpiCall(new Highlight(env, _mainTextBox, Color_CurrentCall));
                    }
                    catch (Exception e)
                    {
                        Utils.MessageBox(e, Utils.StringFormat(Resources.SourceAnalyzer_UnableOpenSource,
                                                               env.FileName, env.LineNumber, e.Message));
                        _mainTextBox.Text = Utils.StringFormat(Resources.SourceAnalyzer_TextBoxCaption, env.Rank, env.FileName, env.LineNumber, env.ToString());
                    }
                }
            }
            else
            {
                // Highlight the correct function for the "main" window.
                if (env.IssueIndex < 0)
                    HighlightMpiCall(new Highlight(env, _mainTextBox, Color_UnissuedCall));
                else
                    HighlightMpiCall(new Highlight(env, _mainTextBox, Color_CurrentCall));
            }

            // Next, work on the "additional" windows. Start with matches.
            Envelope matching = _transitions.GetMatchingTransition(env);
            if (matching != null)
            {
                // Get a textbox to store the file.
                RichTextBox tb = null;
                foreach (RichTextBox r in _additionalTextBoxes)
                {
                    if (r.Tag as string == matching.FileName.ToUpperInvariant())
                    {
                        tb = r;
                        break;
                    }
                }

                // Setup the textbox label.
                Label label = new Label();
                label.AutoSize = true;
                label.Text = Utils.StringFormat(Resources.SourceAnalyzer_TextBoxCaption, matching.Rank, matching.FileName, matching.LineNumber, matching.ToString());

                if (tb == null)
                {
                    tb = new RichTextBox();
                    tb.Dock = DockStyle.Fill;
                    tb.WordWrap = false;
                    tb.ReadOnly = true;
                    tb.BackColor = Color.White;
                    if (matching.LineNumber < 0)
                    {
                        tb.Text = Resources.SourceAnalyzer_UnknownFile;
                        label.Text = Utils.StringFormat(Resources.SourceAnalyzer_TextBoxCaption_UnknownFile, matching.Rank, matching.ToString());
                    }
                    else
                    {
                        try
                        {
                            using (StreamReader sr = new StreamReader(matching.FileName))
                            {
                                tb.Text = sr.ReadToEnd();
                            }
                            tb.Tag = matching.FileName.ToUpperInvariant();
                            HighlightMpiCall(new Highlight(matching, tb, Color_MatchingP2P));
                        }
                        catch (Exception e)
                        {
                            Utils.MessageBox(e, Utils.StringFormat(Resources.SourceAnalyzer_UnableOpenSource,
                                                                   matching.FileName, matching.LineNumber, e.Message));
                            tb.Text = Utils.StringFormat(Resources.SourceAnalyzer_TextBoxCaption,
                                                         matching.Rank, matching.FileName, matching.LineNumber, matching.ToString());
                        }
                    }
                }
                else
                {
                    HighlightMpiCall(new Highlight(matching, tb, Color_MatchingP2P));
                }
                _additionalTextBoxes.Clear();
                _additionalTextBoxes.Add(tb);
                _additionalTextBoxLabels.Clear();
                _additionalTextBoxLabels.Add(label);

                // Add the label and the textbox to the GUI.
                _additionalTextBoxesLayoutPanel.RowCount = 2;
                _additionalTextBoxesLayoutPanel.RowStyles.Clear();
                _additionalTextBoxesLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
                _additionalTextBoxesLayoutPanel.RowStyles.Add(new RowStyle());
                _additionalTextBoxesLayoutPanel.Controls.Clear();
                _additionalTextBoxesLayoutPanel.Controls.Add(label, 0, 0);
                _additionalTextBoxesLayoutPanel.Controls.Add(tb, 0, 1);
            }
            else
            {
                // No single matching for p-2-p, so see if there are collective matchings.
                List<Envelope> matchings = _transitions.GetCollectiveTransitions(env);
                if (matchings != null && matchings.Count > 0)
                {
                    List<RichTextBox> textboxes = new List<RichTextBox>();
                    List<Label> labels = new List<Label>();
                    List<List<Envelope>> mappings = new List<List<Envelope>>();

                    // Go through and assign text boxes to all of the matching collectives.
                    foreach (Envelope commMatching in matchings)
                    {
                        bool found = false;
                        for (int i = 0; i < mappings.Count; i++)
                        {
                            if (mappings[i] != null &&
                                mappings[i][0].LineNumber == commMatching.LineNumber &&
                                mappings[i][0].MpiCallName == commMatching.MpiCallName &&
                                mappings[i][0].FileName.ToUpperInvariant() == commMatching.FileName.ToUpperInvariant())
                            {
                                found = true;
                                mappings[i].Add(commMatching);
                                break;
                            }
                        }

                        if (found == false)
                        {
                            RichTextBox tb = new RichTextBox();
                            tb.Dock = DockStyle.Fill;
                            tb.WordWrap = false;
                            tb.ReadOnly = true;
                            tb.BackColor = Color.White;
                            if (commMatching.FileName == "Unknown" && commMatching.LineNumber < 0)
                            {
                                tb.Text = Resources.SourceAnalyzer_UnknownFile;
                            }
                            else
                            {
                                try
                                {
                                    using (StreamReader sr = new StreamReader(commMatching.FileName))
                                    {
                                        tb.Text = sr.ReadToEnd();
                                    }
                                    tb.Tag = commMatching.FileName.ToUpperInvariant();
                                    HighlightMpiCall(new Highlight(commMatching, tb, Color_MatchingCollective));
                                }
                                catch (Exception e)
                                {
                                    Utils.MessageBox(e, Utils.StringFormat(Resources.SourceAnalyzer_UnableOpenSource,
                                                                           commMatching.FileName, commMatching.LineNumber, e.Message));
                                    tb.Text = Utils.StringFormat(Resources.SourceAnalyzer_TextBoxCaption,
                                                                 commMatching.Rank, commMatching.FileName, commMatching.LineNumber, commMatching.ToString());
                                }
                            }

                            textboxes.Add(tb);
                            mappings.Add(new List<Envelope>());
                            mappings[mappings.Count - 1].Add(commMatching);
                        }
                    }

                    // Clear the GUI.
                    _additionalTextBoxes.Clear();
                    _additionalTextBoxLabels.Clear();
                    _additionalTextBoxesLayoutPanel.Controls.Clear();

                    // Now add to the GUI.
                    float rowHeight = (float)100.0 / (float)textboxes.Count;
                    _additionalTextBoxesLayoutPanel.RowCount = textboxes.Count * 2;
                    _additionalTextBoxesLayoutPanel.RowStyles.Clear();
                    for (int i = 0; i < textboxes.Count; i++)
                    {
                        _additionalTextBoxes.Add(textboxes[i]);

                        // Setup the label.
                        StringBuilder labelText = new StringBuilder();
                        if (mappings[i].Count > 1)
                        {
                            labelText.AppendFormat("Ranks {0}", mappings[i][0].Rank);
                            for (int j = 1; j < mappings[i].Count; j++)
                            {
                                labelText.AppendFormat(", {0}", mappings[i][j].Rank);
                            }
                        }
                        else
                        {
                            labelText.AppendFormat("Rank {0}", mappings[i][0].Rank);
                        }
                        if (mappings[i][0].LineNumber < 0)
                            labelText.Append(" - Unknown File");
                        else
                            labelText.AppendFormat(" - File: {0} - Line: {1}", mappings[i][0].FileName, mappings[i][0].LineNumber);
                        foreach (Envelope e in mappings[i])
                            labelText.AppendFormat("\nRank {0}: {1}", e.Rank, e.ToString());
                        Label label = new Label();
                        label.AutoSize = true;
                        label.Text = labelText.ToString();
                        _additionalTextBoxLabels.Add(label);

                        _additionalTextBoxesLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
                        _additionalTextBoxesLayoutPanel.Controls.Add(label, 0, i * 2);

                        _additionalTextBoxesLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, rowHeight));
                        _additionalTextBoxesLayoutPanel.Controls.Add(textboxes[i], 0, (i * 2) + 1);
                    }
                }
                else
                {
                    _additionalTextBoxesLayoutPanel.Controls.Clear();
                    _additionalTextBoxesLayoutPanel.RowCount = 0;
                    _additionalTextBoxesLayoutPanel.RowStyles.Clear();
                    _additionalTextBoxes.Clear();
                    _additionalTextBoxLabels.Clear();
                }
            }
        }

        private void ResetButtonEnabledState()
        {
            //BeginInvoke((MethodInvoker)delegate
            //{
                _btnFirstTransition.Enabled = _transitions.HasPreviousTransition;
                _btnPreviousTransition.Enabled = _transitions.HasPreviousTransition;
                _btnNextTransition.Enabled = _transitions.HasNextTransition;
                _btnLastTransition.Enabled = _transitions.HasNextTransition;

                _btnFirstInterleaving.Enabled = _transitions.HasPreviousInterleaving;
                _btnPreviousInterleaving.Enabled = _transitions.HasPreviousInterleaving;
                _btnNextInterleaving.Enabled = _transitions.HasNextInterleaving;
                _btnLastInterleaving.Enabled = _transitions.HasNextInterleaving;
        //    });
        }

        #endregion
    }

    #region NoMpiCallException

    public class NoMpiCallException : ApplicationException
    {
        public NoMpiCallException()
            : base()
        {
        }

        public NoMpiCallException(string message)
            : base(message)
        {
        }
    }

    #endregion
}
